#include <utility>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <time.h>
#include "basic_cpp.hpp"
#include "matrix_operations.hpp"
#include "basic_opencl.hpp"
#include "coo_opencl.hpp"
#include "csr_opencl.hpp"
#include "cds_opencl.hpp"
#include "ellpack_opencl.hpp"
#include "init_opencl.hpp"
#include "atomic_test.hpp"
#include "ellpack_opencl_twodev.hpp"
#include "csr_opencl_twodev.hpp"

using namespace std;

float * answer;

void testWithMatrix(OpenCLEnv openCLEnv, string name) {
    int nrTimes = 1000;

	/* Import the matrix, vector. */
    MatrixOperations matrix = MatrixOperations(name, 1, -1);
	MatrixOperations v = MatrixOperations("vector.mtx", 1, matrix.getNumCols());

	/* BASIC CPP */
	answer = findProduct(matrix, v, nrTimes);
	delete[] answer; //del dynamic array

	/* BASIC OPENCL */
	answer = findProductOCL(openCLEnv, matrix, v, nrTimes, false);
	delete[] answer; //del dynamic array

	/* Convert to COO / CSR format. */
	matrix.cooPackMatrix();

	/* COO OPENCL */
	answer = findProductCooOCL(openCLEnv, matrix, v, nrTimes);
	delete[] answer; //del dynamic array

	/* CSR OPENCL */
	answer = findProductCsrOCL(openCLEnv, matrix, v, nrTimes, false);
	delete[] answer; //del dynamic array

	/* CSR OPENCL, TWO DEVICES */
	answer = findProductCsrOCLTwoDev(openCLEnv, matrix, v, nrTimes);
	delete[] answer; //del dynamic array

	/* Convert to ELLPACK format. */
	matrix.ellPackMatrix();

	/* ELLPACK OPENCL WITH VECTOR AS IMAGE */
	answer = findProductEllPackOCL(openCLEnv, matrix, v, nrTimes, true);
	delete[] answer; //del dynamic array

	/* ELLPACK OPENCL */
	answer = findProductEllPackOCL(openCLEnv, matrix, v, nrTimes, false);
	delete[] answer; //del dynamic array

	/*ELLPACK OPENCL, TWO DEVICES */
	answer = findProductEllPackOCLTwoDev(openCLEnv, matrix, v, nrTimes);
	delete[] answer; //del dynamic array

	/* Convert to CDS format. */
	matrix.cdsPackMatrix();

	/* CDS OPENCL*/
	answer = findProductCdsOCL(openCLEnv, matrix, v, nrTimes,false);
	delete[] answer; //del dynamic array
}

void testAtomics(OpenCLEnv openCLEnv) {
    answer = atomicTest(openCLEnv,1);
	delete[] answer; //del dynamic array
}

int main() {
	/* Initialize OpenCL */
    OpenCLEnv openCLEnv;

	/* Test with different matrices. */
    testWithMatrix(openCLEnv, "heart1.mtx");
    testWithMatrix(openCLEnv, "Trefethen_20000b.mtx");
    testWithMatrix(openCLEnv, "TSOPF_RS_b162_c3.mtx");
    testWithMatrix(openCLEnv, "psmigr_1.mtx");
    testWithMatrix(openCLEnv, "spiral.mtx");
    testWithMatrix(openCLEnv, "viscoplastic1.mtx");
    testWithMatrix(openCLEnv, "deter4.mtx");
    testWithMatrix(openCLEnv, "Maragal_2.mtx");
    testWithMatrix(openCLEnv, "fp.mtx");

    testAtomics(openCLEnv);

	return 0;
}
